package com.sxt.provider.sp.excutor;

import com.sxt.commons.typeEnum.ApiTypeEnum;
import com.sxt.commons.typeEnum.ChannelTypeEnum;
import com.sxt.commons.xml.XmlUtils;
import com.sxt.pojo.entity.Order;
import com.sxt.provider.sp.SpApiConfigService;
import com.sxt.provider.sp.SpConfigService;
import com.sxt.provider.util.MyX509TrustManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.apache.http.util.TextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.*;

public abstract class AbstractExcutor {

    protected final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    SpApiConfigService spApiConfigService;

    @Autowired
    SpConfigService spConfigService;

    public Map<String, Object> excutor(Order order) throws Exception {
        return excutor(order, null);
    }

    /**
     * 组装订单，sp-api-config、其他特别参数
     * @param order
     * @param extendOrderParams
     * @return
     * @throws Exception
     */
    public Map<String, Object> excutor(Order order, Map<String, Object> extendOrderParams) throws Exception {
        Assert.notNull(order, "无效的订单信息");
        Map<String, Object> apiConfigParams = getApiFixParams(order.getSpId(),
                ChannelTypeEnum.getByType(order.getChannelType()));//获取sp-api-config

        Map<String, Object> spConfigParams = getSpConfig(order.getSpId());//获取sp-config
        Map<String, Object> apiParams = getApiParams(order, apiConfigParams, extendOrderParams);//整合order、特别参数、sp-api-config

        return run(spConfigParams, apiParams);
    }

    protected Map<String, Object> getApiFixParams(Long spid, ChannelTypeEnum channelTypeEnum) {
        return spApiConfigService.getKeyValues(
                spid,
                channelTypeEnum,
                this.getApiTypeEnum());
    }

    protected Map<String, Object> getSpConfig(Long spid) {
        Map<String, Object> result = spConfigService.getKeyValues(spid);
        return result;
    }

    protected abstract ApiTypeEnum getApiTypeEnum();

    protected abstract Map<String, Object> getApiParams(Order order, Map<String, Object> spconfig, Map<String, Object> extendOrderParams);

    /**
     * 组装sp参数，和其他参数
     * @param spConfig
     * @param params
     * @return
     * @throws Exception
     */
    protected abstract Map<String, Object> run(Map<String, Object> spConfig,
                                               Map<String, Object> params) throws Exception;

    /**
     * post+xml发送请求
     * @param params
     * @param url
     * @return
     */
    protected String sendPostXml(Map<String, Object> params, String url) {
        HttpClient client = new DefaultHttpClient();
        String result = null;
        HttpPost post = new HttpPost(url);
        try {
            if (null != params) {
                String strBody = XmlUtils.toString(params, "xml");
                logger.info(getClass().getName() +
                        " pay sendPost request body : " +
                        strBody + ", request url:" + url);
                StringEntity entity = new StringEntity(strBody, "utf-8");
                entity.setContentEncoding("UTF-8");
                entity.setContentType("application/xml");
                post.setEntity(entity);
            }

            HttpResponse resultResp = client.execute(post);

            if (resultResp.getStatusLine().getStatusCode() == 200) {
                try {
                    result = EntityUtils.toString(resultResp.getEntity(), "utf8");
                } catch (Exception e) {
                    logger.error(e.toString());
                }
            }
            logger.info(getClass().getName() +
                    "pay sendPost response body : " + result + ", request url:" + url);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.toString());
        }
        return result;
    }


    /**
     * post+form
     * @param params
     * @param url
     * @return
     */
    protected String sendPostForm(Map<String, Object> params, String url) {
        final HttpParams httpParams = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParams, 30000);
        HttpConnectionParams.setSoTimeout(httpParams,30000);
        HttpClient client = new DefaultHttpClient(httpParams);

        String result = null;

        HttpPost post = new HttpPost(url);
        try {
            if (null != params) {
                logger.info(getClass().getName() +
                        " pay sendPost request body : " +
                        params + ", request url:" + url);
                List<NameValuePair> pairList = new ArrayList<NameValuePair>(params.size());
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry
                            .getValue().toString());
                    pairList.add(pair);
                }
                post.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8")));
            }

            HttpResponse resultResp = client.execute(post);

            if (resultResp.getStatusLine().getStatusCode() == 200) {
                try {
                    result = EntityUtils.toString(resultResp.getEntity(), "utf8");
                    logger.info(getClass().getName() +
                            "pay sendPost response body : " + result + ", request url:" + url);
                } catch (Exception e) {
                    logger.error(e.toString());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.toString());
        }
        return result;
    }

    /**
     * 根据key，获取map中的值
     * @param params
     * @param key
     * @return
     */
    protected Object getVal(Map<String, Object> params, String key) {
        Assert.notNull(params, "找不到" + key);
        Assert.isTrue(params.containsKey(key), "找不到" + key);
        Object val = params.get(key);
        Assert.notNull(val, "找不到" + key);
        return val;
    }

    /**
     * 处理http请求  requestUrl为请求地址  requestMethod请求方式，值为"GET"或"POST"
     */
    public static String sendHttpRequest(String requestUrl,String requestMethod,String outputStr){
        StringBuffer buffer=null;
        try{
            URL url=new URL(requestUrl);
            HttpURLConnection conn=(HttpURLConnection)url.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod(requestMethod);
            conn.connect();
            //往服务器端写内容 也就是发起http请求需要带的参数
            if(null!=outputStr){
                OutputStream os=conn.getOutputStream();
                os.write(outputStr.getBytes("utf-8"));
                os.close();
            }

            //读取服务器端返回的内容
            InputStream is=conn.getInputStream();
            InputStreamReader isr=new InputStreamReader(is,"utf-8");
            BufferedReader br=new BufferedReader(isr);
            buffer=new StringBuffer();
            String line=null;
            while((line=br.readLine())!=null){
                buffer.append(line);
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return buffer.toString();
    }


    /*
     * 处理https GET/POST请求
     * 请求地址、请求方法、参数
     * */
    public static String sendHttpsRequest(String requestUrl,String requestMethod,String outputStr){
        StringBuffer buffer=null;
        try{
            //创建SSLContext
            SSLContext sslContext=SSLContext.getInstance("SSL");
            TrustManager[] tm={new MyX509TrustManager()};
            //初始化
            sslContext.init(null, tm, new java.security.SecureRandom());;
            //获取SSLSocketFactory对象
            SSLSocketFactory ssf=sslContext.getSocketFactory();
            URL url=new URL(requestUrl);
            HttpsURLConnection conn=(HttpsURLConnection)url.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod(requestMethod);
            //设置当前实例使用的SSLSoctetFactory
            conn.setSSLSocketFactory(ssf);
            conn.connect();
            //往服务器端写内容
            if(null!=outputStr){
                OutputStream os=conn.getOutputStream();
                os.write(outputStr.getBytes("utf-8"));
                os.close();
            }

            //读取服务器端返回的内容
            InputStream is=conn.getInputStream();
            InputStreamReader isr=new InputStreamReader(is,"utf-8");
            BufferedReader br=new BufferedReader(isr);
            buffer=new StringBuffer();
            String line=null;
            while((line=br.readLine())!=null){
                buffer.append(line);
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return buffer.toString();
    }
    /**
     * 生成可以提交的表单页面
     * @param paramMap
     * @param actionUrl
     * @return
     */
    public String generateSubmitHtml(Map<String, Object> paramMap,String actionUrl) {

        StringBuilder html = new StringBuilder();
        html.append("<html><head></head><body>").append("<form id='pay_form' name='pay_form' action='")
                .append(actionUrl).append("' method='POST'>\n");

        for (String key : paramMap.keySet()) {
            String value = paramMap.get(key).toString();
            //银联快捷，输入验证码输入框的不隐藏
            if("verifyCode".equals(key))html.append("<input type='text' name='" + key + "' value='" + value + "'>\n");
            if( value!= null && !value.isEmpty()){
                html.append("<input type='hidden' name='" + key + "' value='" + value + "'>\n");

            }
        }

        html.append("</form>\n")
                .append("<script language='javascript'>window.onload=function(){document.pay_form.submit();}</script>\n")
                .append("</body></html>");

        return html.toString();
    }

    /**
     * 把map的参数自然顺序排序
     * @param paramMap
     * @return
     */
    public String  getParamStr(Map<String , Object> paramMap){
        SortedMap<String, Object> smap = new TreeMap<String, Object>(paramMap);
        StringBuffer stringBuffer = new StringBuffer();
        for (Map.Entry<String, Object> m : smap.entrySet()) {
            Object value = m.getValue();
            if (value != null && StringUtils.isNotBlank(String.valueOf(value))){
                stringBuffer.append(m.getKey()).append("=").append(value).append("&");
            }
        }
        stringBuffer.delete(stringBuffer.length() - 1, stringBuffer.length());
        return stringBuffer.toString();
    }

    /**
     * form-data发送方式
     * @param textMap
     * @param urlStr
     * @return
     */
    public String sendPostFormData(Map<String, Object> textMap,String urlStr) {
        String res = "";
        HttpURLConnection conn = null;
        // boundary就是request头和上传文件内容的分隔符
        String BOUNDARY = "---------------------------123821742118716";
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("User-Agent",
                    "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type",
                    "multipart/form-data; boundary=" + BOUNDARY);
            OutputStream out = new DataOutputStream(conn.getOutputStream());
            // text
            if (textMap != null) {
                StringBuffer strBuf = new StringBuffer();
                Iterator iter = textMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue =  entry.getValue().toString();
                    if (inputValue == null) {
                        continue;
                    }
                    strBuf.append("\r\n").append("--").append(BOUNDARY)
                            .append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""
                            + inputName + "\"\r\n\r\n");
                    strBuf.append(inputValue);
                }
                out.write(strBuf.toString().getBytes());
            }

            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();
            // 读取返回数据
            StringBuffer strBuf = new StringBuffer();
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
            reader.close();
            reader = null;
            System.out.println("resresres---"+res);
        } catch (Exception e) {
            System.out.println("发送POST请求出错。" + urlStr);
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return res;
    }


    public static String sendPostJson(String urlPath, String Json) {
        // HttpClient 6.0被抛弃了
        String result = "";
        BufferedReader reader = null;
        try {
            URL url = new URL(urlPath);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("Content-Type","application/json; charset=UTF-8");
            // 设置接收类型否则返回415错误
            //conn.setRequestProperty("accept","*/*")此处为暴力方法设置接受所有类型，以此来防范返回415;
            conn.setRequestProperty("accept","application/json");
            // 往服务器里面发送数据
            if (Json != null && !TextUtils.isEmpty(Json)) {
                byte[] writebytes = Json.getBytes();
                // 设置文件长度
                conn.setRequestProperty("Content-Length", String.valueOf(writebytes.length));
                //OutputStream outwritestream = conn.getOutputStream();
                DataOutputStream outwritestream = new DataOutputStream(
                        conn.getOutputStream());
                outwritestream.write(Json.getBytes());
                outwritestream.flush();
                outwritestream.close();
            }
            reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));

            String lines;
            StringBuffer sb = new StringBuffer("");
            while ((lines = reader.readLine()) != null) {
                lines = new String(lines.getBytes(), "utf-8");
                sb.append(lines);
            }
            result = sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
}



